package com.xqy.wexmini.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.xqy.wexmini.common.Result;
import com.xqy.wexmini.config.JwtSecurityProperties;
import com.xqy.wexmini.constant.Constant;
import com.xqy.wexmini.domain.User;
import com.xqy.wexmini.service.AuthService;
import com.xqy.wexmini.service.UserService;
import com.xqy.wexmini.service.dto.AuthUserDto;
import com.xqy.wexmini.utils.JwtTokenUtils;
import com.xqy.wexmini.utils.NetworkUtils;
import com.xqy.wexmini.utils.RedisUtils;
import com.xqy.wexmini.wechat.service.WxMiniApi;
import com.xqy.wexmini.wechat.utils.WeChatUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Service
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class AuthServiceImpl implements AuthService {

    @Value("${wxMini.appId}")
    private String appId;
    @Value("${wxMini.secret}")
    private String secret;

    @Autowired
    private JwtTokenUtils jwtTokenUtils;
    @Autowired
    private WxMiniApi wxMiniApi;
    @Autowired
    private UserService userService;
    @Autowired
    private JwtSecurityProperties properties;
    @Autowired
    private RedisUtils redisUtils;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<AuthUserDto>  login(AuthUserDto authUserDto, HttpServletRequest request) {
        // 通过缓存判断同一IP某一时间段内的登录次数是否超出限定次数
        String ip = NetworkUtils.getIp(request);
        String requestLoginIp = "request_login_".concat(ip);
        long loginCount = redisUtils.increment(requestLoginIp, 1L);
        if (loginCount == 1) {
            redisUtils.expire(requestLoginIp, Constant.REQUEST_LOGIN_LIMIT_TIME);
        }
        if (loginCount > Constant.REQUEST_LOGIN_LIMIT_COUNT) {
            log.warn("IP:[".concat(ip).concat("]已超出限定次数"));
            throw new RuntimeException("时间段内已超出限定次数,请不要频繁登录!");
        }

        Result<AuthUserDto> result = new Result<>();


        JSONObject jsonObject = wxMiniApi.authCode2Session(appId, secret, authUserDto.getCode());
        if (jsonObject == null) {
            throw new RuntimeException("调用微信端授权认证接口错误");
        }
        String openId = jsonObject.getString(Constant.OPEN_ID);
        String sessionKey = jsonObject.getString(Constant.SESSION_KEY);
        String unionId = jsonObject.getString(Constant.UNION_ID);
        if (StringUtils.isEmpty(openId)) {
            return result.error(jsonObject.getString(Constant.ERR_CODE), jsonObject.getString(Constant.ERR_MSG));
        }
        authUserDto.setOpenId(openId);

        //判断用户表中是否存在该用户，不存在则进行解密得到用户信息，并进行新增用户
        Result<User> resultUser = new Result<User>().ok(userService.findByOpenId(openId));
        if (resultUser.getModule() == null) {
            System.out.println(authUserDto.getEncryptedData());
            System.out.println(sessionKey);
            System.out.println(authUserDto.getIv());
            System.out.println(openId);
            String userInfo = WeChatUtil.wxDecrypt(authUserDto.getEncryptedData(), sessionKey, authUserDto.getIv());
            System.out.println(userInfo);
            if (StringUtils.isEmpty(userInfo)) {
                throw new RuntimeException("解密用户信息错误");
            }
            String[] s1 = userInfo.split(",\"watermark");
            String aa=s1[0]+"}";
            System.out.println(aa);
            User user = JSONObject.parseObject(aa, User.class);
            System.out.println("////////");
            System.out.println(user);
            if (user == null) {
                throw new RuntimeException("填充用户对象错误");
            }
            user.setUnionId(unionId);
            user.setOpenId(openId);
            user.setUserName(user.getNickName());
            userService.insert(user);
            authUserDto.setUserInfo(user);

        } else {
            authUserDto.setUserInfo(resultUser.getModule());
        }

        //创建token
        Map<String, Object> claims = new HashMap<>(16);
        claims.put("roles", "user");
        String token = jwtTokenUtils.createToken(authUserDto.getOpenId(), claims);
        if (StringUtils.isEmpty(token)) {
            throw new RuntimeException("生成token错误");
        }

        authUserDto.setToken(properties.getTokenStartWith() + token);

        // 将当前用户信息与登录时间写入Redis缓存的哈希表
        String key = authUserDto.getOpenId();
        redisUtils.hashSet(key, "id", authUserDto.getUserInfo().getId());
        redisUtils.hashSet(key, "nickName", authUserDto.getUserInfo().getNickName());
        redisUtils.hashSet(key, "avatarUrl", authUserDto.getUserInfo().getAvatarUrl());
        redisUtils.hashSet(key, "lastLoginTime", Timestamp.valueOf(LocalDateTime.now()));
        redisUtils.hashSet(key, "ip", ip);

        return result.ok(authUserDto);
    }
}
